﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CodeGenerationPipeline.Contracts;
using System.Reflection;
using AbstraX.Bindings;
using ImpromptuInterface;
using ImpromptuInterface.Dynamic;
using AbstraX.ServerInterfaces;
using CodeGenerationPipeline.PackageElements;
using Metaspec;
using System.Diagnostics;
using AbstraX.Contracts;
using AbstraX.BindingsTreeEntities;

namespace CodeGenerationPipeline
{
    public static class Extensions
    {
        // this class is here to simply support Fluent style programming

        public static IServiceType ApplyPortType(this IPackage package, Type type)
        {
            var basePackage = (BasePackage)package;
            var codeGenerationPackage = new CodeGenerationPackage(type, basePackage.Builds);

            basePackage.CodeGenerationPackage = codeGenerationPackage;

            return basePackage.ActLike<IServiceType>();
        }

        public static IServiceType ApplyPortType(this IPackage package, CsClass portClass)
        {
            var basePackage = (BasePackage)package;
            var codeGenerationPackage = new CodeGenerationPackage(portClass, basePackage.Builds);

            basePackage.CodeGenerationPackage = codeGenerationPackage;

            return basePackage.ActLike<IServiceType>();
        }

        public static IServiceType AddGenericArgument(this IServiceType serviceType, Type type)
        {
            var basePackage = (BasePackage)serviceType.GetType().GetProperty("Original").GetGetMethod().Invoke(serviceType, null);

            return basePackage.ActLike<IServiceType>();
        }

        public static IServiceType AddParameter(this IServiceType serviceType, Func<Type, object> func)
        {
            var basePackage = (BasePackage)serviceType.GetType().GetProperty("Original").GetGetMethod().Invoke(serviceType, null);

            return basePackage.ActLike<IServiceType>();
        }

        public static IDataContextSupporter Support(this IServiceType serviceType)
        {
            var basePackage = (BasePackage)serviceType.GetType().GetProperty("Original").GetGetMethod().Invoke(serviceType, null);

            return basePackage.ActLike<IDataContextSupporter>();
        }

        public static IDataContextSupportMapper MapAllOperations(this IDataContextSupporter dataContextSupporter, Func<Type, IElement, OptionalDataContextOperation, MemberInfo> func)
        {
            var basePackage = (BasePackage)dataContextSupporter.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupporter, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapAllOperations(this IDataContextSupporter dataContextSupporter, Func<CsClass, IElement, OptionalDataContextOperation, CsNode> func)
        {
            var basePackage = (BasePackage)dataContextSupporter.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupporter, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper When(this IDataContextSupporter dataContextSupporter, Func<OptionalDataContextOperation> func)
        {
            var basePackage = (BasePackage)dataContextSupporter.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupporter, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;

            codeGenerationPackage.CurrentWhenFilter = func();

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper When(this IDataContextSupportMapper dataContextSupportMapper, Func<OptionalDataContextOperation> func)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;

            codeGenerationPackage.CurrentWhenFilter = func();

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IDataContextSupportMapper dataContextSupportMapper, Func<Type, IElement, OptionalDataContextOperation, MemberInfo> func)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IObjectContext objectContext, Func<CsClass, IElement, OptionalDataContextOperation, CsNode> func)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapAllOperations(this IDataContextSupporter dataContextSupporter, Func<Type, IElement, DefaultDataContextOperation, MemberInfo> func)
        {
            var basePackage = (BasePackage)dataContextSupporter.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupporter, null);

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapAllOperations(this IDataContextSupporter dataContextSupporter, Func<CsClass, IElement, DefaultDataContextOperation, CsNode> func)
        {
            var basePackage = (BasePackage)dataContextSupporter.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupporter, null);

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper When(this IDataContextSupporter dataContextSupporter, Func<DefaultDataContextOperation> func)
        {
            var basePackage = (BasePackage)dataContextSupporter.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupporter, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;

            codeGenerationPackage.CurrentWhenFilter = func();

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper When(this IDataContextSupportMapper dataContextSupportMapper, Func<DefaultDataContextOperation> func)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;

            codeGenerationPackage.CurrentWhenFilter = func();

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IObjectContext objectContext, Func<Type, IElement, OptionalDataContextOperation, MemberInfo> func)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;
            var dataContextOperation = (OptionalDataContextOperation)codeGenerationPackage.CurrentWhenFilter;

            foreach (var build in codeGenerationPackage.ElementBuilds.Values)
            {
            }

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IDataContextSupportMapper dataContextSupportMapper, Func<CsClass, IElement, OptionalDataContextOperation, CsNode> func)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;
            var dataContextOperation = (OptionalDataContextOperation)codeGenerationPackage.CurrentWhenFilter;

            foreach (var build in codeGenerationPackage.ElementBuilds.Values)
            {
                CsNode member = func(codeGenerationPackage.PortType.ServiceClass, build.Element, dataContextOperation);

                Debug.WriteLine(((CsMethod)member).identifier.identifier);
            }

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IDataContextSupportMapper dataContextSupportMapper, Func<Type, IElement, DefaultDataContextOperation, MemberInfo> func)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;
            var dataContextOperation = (DefaultDataContextOperation)codeGenerationPackage.CurrentWhenFilter;

            foreach (var build in codeGenerationPackage.ElementBuilds.Values)
            {
            }

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IObjectContext objectContext, Func<Type, IElement, DefaultDataContextOperation, MemberInfo> func)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;
            var dataContextOperation = (DefaultDataContextOperation)codeGenerationPackage.CurrentWhenFilter;

            foreach (var build in codeGenerationPackage.ElementBuilds.Values)
            {
            }

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IDataContextSupportMapper dataContextSupportMapper, Func<CsClass, IElement, DefaultDataContextOperation, CsNode> func)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;
            var dataContextOperation = (DefaultDataContextOperation)codeGenerationPackage.CurrentWhenFilter;

            foreach (var build in codeGenerationPackage.ElementBuilds.Values)
            {
                CsNode member = func(codeGenerationPackage.PortType.ServiceClass, build.Element, dataContextOperation);

                Debug.WriteLine(((CsMethod)member).identifier.identifier);
            }

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IDataContextSupportMapper MapOperation(this IObjectContext objectContext, Func<CsClass, IElement, DefaultDataContextOperation, CsNode> func)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);
            var codeGenerationPackage = basePackage.CodeGenerationPackage;
            var dataContextOperation = (DefaultDataContextOperation)codeGenerationPackage.CurrentWhenFilter;

            foreach (var build in codeGenerationPackage.ElementBuilds.Values)
            {
                CsNode member = func(codeGenerationPackage.PortType.ServiceClass, build.Element, dataContextOperation);

                Debug.WriteLine(((CsMethod)member).identifier.identifier);
            }

            return basePackage.ActLike<IDataContextSupportMapper>();
        }

        public static IObjectContext Create(this IDataContextSupportMapper dataContextSupportMapper, Type type)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);

            return basePackage.ActLike<IObjectContext>();
        }

        public static IObjectContext Return(this IDataContextSupportMapper dataContextSupportMapper, Type type)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);

            return basePackage.ActLike<IObjectContext>();
        }

        public static IObjectContext MapMember(this IObjectContext objectContext, Func<Type, MemberInfo> func)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);

            return basePackage.ActLike<IObjectContext>();
        }

        public static IObjectContext MapParm(this IObjectContext objectContext, Func<Type, MemberInfo> func)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);

            return basePackage.ActLike<IObjectContext>();
        }

        public static IRequirements Requirements(this IDataContextSupportMapper dataContextSupportMapper)
        {
            var basePackage = (BasePackage)dataContextSupportMapper.GetType().GetProperty("Original").GetGetMethod().Invoke(dataContextSupportMapper, null);

            return basePackage.ActLike<IRequirements>();
        }

        public static IRequirements Requirements(this IObjectContext objectContext)
        {
            var basePackage = (BasePackage)objectContext.GetType().GetProperty("Original").GetGetMethod().Invoke(objectContext, null);

            return basePackage.ActLike<IRequirements>();
        }

        public static IRequirements AddIncludeFile(this IRequirements requirements, string path, string type, BuildAction buildAction, string customTool, string customNamespace)
        {
            var basePackage = (BasePackage)requirements.GetType().GetProperty("Original").GetGetMethod().Invoke(requirements, null);

            return basePackage.ActLike<IRequirements>();
        }

        public static IRequirements AddRequiredPackage(this IRequirements requirements, string name, string path, string type)
        {
            var basePackage = (BasePackage)requirements.GetType().GetProperty("Original").GetGetMethod().Invoke(requirements, null);

            return basePackage.ActLike<IRequirements>();
        }

        public static IRequirements AddRequiredImport(this IRequirements requirements, string nameSpace)
        {
            var basePackage = (BasePackage)requirements.GetType().GetProperty("Original").GetGetMethod().Invoke(requirements, null);

            return basePackage.ActLike<IRequirements>();
        }

        public static IRequirements AddRequiredConfiguration(this IRequirements requirements, string path, string configXML)
        {
            var basePackage = (BasePackage)requirements.GetType().GetProperty("Original").GetGetMethod().Invoke(requirements, null);

            return basePackage.ActLike<IRequirements>();
        }

        public static ICodeGenerationPackage BuildPackage(this IRequirements requirements)
        {
            var basePackage = (BasePackage)requirements.GetType().GetProperty("Original").GetGetMethod().Invoke(requirements, null);

            return basePackage.CodeGenerationPackage;
        }

        public static string GetName(this Enum _enum)
        {
            return Enum.GetName(_enum.GetType(), _enum);
        }
    }
}
